#include "stm8s.h"
#include "sys_eeprom.h"
#include "stm8s_flash.h"
#include <stdio.h>


// -------------------------- 私有辅助函数 --------------------------
/**
 * @brief  EEPROM解锁（内部使用，确保操作前解锁）
 * @retval EEPROM_OK: 解锁成功；EEPROM_ERR_BUSY: 解锁忙
 */
static uint8_t eeprom_unlock(void)
{
    // 检查是否已解锁
    if (FLASH_GetFlagStatus(FLASH_FLAG_DUL) == SET)
    {
        return EEPROM_OK;  // 已解锁，直接返回
    }
    
    // 执行解锁操作
    FLASH_Unlock(FLASH_MEMTYPE_DATA);  // 解锁EEPROM（数据存储器）
    
    // 等待解锁完成（超时保护，避免死等）
    uint16_t timeout = 0xFFFFU;
    while ((FLASH_GetFlagStatus(FLASH_FLAG_DUL) == RESET) && (timeout-- > 0));
    
    if (timeout == 0)
    {
        return EEPROM_ERR_BUSY;  // 超时，解锁失败
    }
    return EEPROM_OK;
}

/**
 * @brief  等待EEPROM操作完成（内部使用，避免操作冲突）
 * @retval EEPROM_OK: 操作完成；EEPROM_ERR_BUSY: 操作超时
 */
static uint8_t eeprom_wait_operation_done(void)
{
    // 等待操作完成标志（EOP）置位，或超时
    uint16_t timeout = 0xFFFFU;
    while ((FLASH_GetFlagStatus(FLASH_FLAG_EOP) == RESET) && (timeout-- > 0));
    
    if (timeout == 0)
    {
        return EEPROM_ERR_BUSY;  // 超时，操作未完成
    }
    
    return EEPROM_OK;
}

// -------------------------- 公有函数实现 --------------------------
uint8_t eeprom_check_address(uint16_t address)
{
    // 检查地址是否在EEPROM范围内
    if ((address >= EEPROM_START_ADDR) && (address < EEPROM_END_ADDR))
    {
        return EEPROM_OK;
    }
    return EEPROM_ERR_ADDR;
}

uint8_t eeprom_write_byte(uint16_t address, uint8_t data)
{
    // 1. 检查地址合法性  
     address= EEPROM_START_ADDR +address;
    if (eeprom_check_address(address) != EEPROM_OK)
    {
        return EEPROM_ERR_ADDR;
    }

    // 2. EEPROM解锁
    if (eeprom_unlock() != EEPROM_OK)
    {
        return EEPROM_ERR_BUSY;
    }
    FLASH_EraseByte(address);
    // 3. 执行字节写入
    FLASH_ProgramByte(address, data);
    
    // 4. 等待写入完成
    if (eeprom_wait_operation_done() != EEPROM_OK)
    {
        return EEPROM_ERR_BUSY;
    }
    
    return EEPROM_OK;
}

uint8_t eeprom_read_byte(uint16_t address)
{
     address= EEPROM_START_ADDR +address;
    // 检查地址合法性，非法则返回0xFF
    if (eeprom_check_address(address) != EEPROM_OK)
    {
        return 0xFF;
    }
    
    // 直接读取地址数据（EEPROM读取无需解锁）
    return *(volatile uint8_t*)(address);
}



uint8_t eeprom_write_word(uint16_t address, uint32_t data)
{
         address= EEPROM_START_ADDR +address;
    // 1. 检查地址合法性（需4字节对齐 + 在EEPROM范围内）
    if ((eeprom_check_address(address) != EEPROM_OK) || (address & 0x03U) != 0)
    {
        return EEPROM_ERR_ADDR;  // 地址未4字节对齐或超出范围
    }
    
    // 2. EEPROM解锁
    if (eeprom_unlock() != EEPROM_OK)
    {
        return EEPROM_ERR_BUSY;
    }
    // 3. 执行字写入（32位）
    FLASH_ProgramWord(address, data);
    
    // 4. 等待写入完成
    if (eeprom_wait_operation_done() != EEPROM_OK)
    {
        return EEPROM_ERR_BUSY;
    }
    
    return EEPROM_OK;
}

uint32_t eeprom_read_word(uint16_t address)
{
         address= EEPROM_START_ADDR +address;
    // 检查地址合法性（需4字节对齐 + 在EEPROM范围内）
    if ((eeprom_check_address(address) != EEPROM_OK) || (address & 0x03U) != 0)
    {
        return 0xFFFFFFFF;  // 地址错误，返回无效值
    }
    // 直接读取32位数据
    return *(volatile uint32_t*)address;
}

uint8_t eeprom_write_buffer(uint16_t address, uint8_t* buffer, uint16_t len)
{
    // 1. 检查参数合法性（地址范围 + 缓冲区非空 + 长度非0 + 不越界）
    if ((buffer == NULL) || (len == 0))
    {
        return EEPROM_ERR_NULL_PTR;  // 缓冲区空或长度为0
    }    
      address= EEPROM_START_ADDR +address;
    if ((eeprom_check_address(address) != EEPROM_OK) || 
        (address + len > EEPROM_END_ADDR))  // 检查是否越界
    {
        return EEPROM_ERR_ADDR;
    }
    
    // 2. EEPROM解锁
    if (eeprom_unlock() != EEPROM_OK)
    {
        return EEPROM_ERR_BUSY;
    }

    // 3. 逐字节写入缓冲区数据
    for (uint16_t i = 0; i < len; i++)
    {
        FLASH_ProgramByte(address + i, buffer[i]);
        
        // 等待当前字节写入完成
        if (eeprom_wait_operation_done() != EEPROM_OK)
        {
            return EEPROM_ERR_BUSY;  // 某字节写入超时，返回失败
        }
    }
    
    return EEPROM_OK;
}

void eeprom_read_buffer(uint16_t address, uint8_t* buffer, uint16_t len)
{
          address= EEPROM_START_ADDR +address;
    // 检查参数合法性（缓冲区非空 + 地址范围 + 不越界）
    if ((buffer == NULL) || (len == 0) || 
        (eeprom_check_address(address) != EEPROM_OK) || 
        (address + len > EEPROM_END_ADDR))
    {
        return;  // 参数错误，不执行读取
    }

    // 逐字节读取数据到缓冲区
    for (uint16_t i = 0; i < len; i++)
    {
        buffer[i] = *(volatile uint8_t*)(address + i);
    }
}

uint8_t eeprom_erase_block(uint16_t block_num)
{
    // 1. 检查块号合法性（块号需在0~总块数-1范围内）
    if (block_num >= EEPROM_TOTAL_BLOCKS)
    {
        return EEPROM_ERR_ADDR;
    }
    
    // 2. 计算块起始地址
    uint16_t block_addr = EEPROM_START_ADDR + (block_num * EEPROM_BLOCK_SIZE);
    
    // 3. EEPROM解锁
    if (eeprom_unlock() != EEPROM_OK)
    {
        return EEPROM_ERR_BUSY;
    }
    
    // 4. 执行块擦除（STM8S EEPROM擦除以块为单位）
    FLASH_EraseBlock(block_num, FLASH_MEMTYPE_DATA);
    
    // 5. 等待擦除完成
    if (eeprom_wait_operation_done() != EEPROM_OK)
    {
        return EEPROM_ERR_ERASE;  // 擦除超时，返回失败
    }
    
    // 6. 验证擦除结果（随机读取块内1个地址，确认是否为0xFF）
    if (*(volatile uint8_t*)block_addr != 0xFF)
    {
        return EEPROM_ERR_ERASE;  // 擦除不彻底，返回失败
    }
    
    return EEPROM_OK;
}

/**
 * @brief EEPROM read/write test command function
 * @param argc Number of command arguments
 * @param argv Array of command arguments
 * @return Test result: 0 for success, non-zero for failure
 * @details This function tests all EEPROM operations including byte, half-word, 
 *          word and buffer read/write operations, as well as block erase functionality
 */
int cmd_eeprom_test(int argc, char **argv)
{
    uint8_t test_byte = 0x5A;
    uint16_t test_half_word = 0x1234;
    uint32_t test_word = 0x12345678;
    uint8_t test_buffer[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
    uint8_t read_buffer[10];
    uint16_t test_address = 0x00;
    uint8_t result;
    
    // Print test start message
    printf("Starting EEPROM test...\r\n");

    // Test byte write and read
    printf("Testing byte write/read...\r\n");
    result = eeprom_write_byte(test_address, test_byte);
    if (result) {
        printf("ERROR: Byte write failed %d\r\n",result);
        return -1;  // Byte write failed
    }


    if (eeprom_read_byte(test_address) != test_byte) {
        printf("ERROR: Byte read data mismatch. Expected: 0x%02X, Got: 0x%02X\r\n", 
               test_byte, eeprom_read_byte(test_address));
        return -2;  // Byte read data mismatch
    }
    printf("Byte write/read test PASSED\r\n");


    // Test word write and read
    printf("Testing word write/read...\r\n");
    result = eeprom_write_word(test_address + 4, test_word);
    if (result) {
        printf("ERROR: Word write failed\r\n");
        return -5;  // Word write failed
    }

    if (eeprom_read_word(test_address + 4) != test_word) {
        printf("ERROR: Word read data mismatch. Expected: 0x%08X, Got: 0x%08X\r\n", 
               test_word, eeprom_read_word(test_address + 4));
        return -6;  // Word read data mismatch
    }
    printf("Word write/read test PASSED\r\n");

    // Test buffer write and read
    printf("Testing buffer write/read...\r\n");
    result = eeprom_write_buffer(test_address + 8, test_buffer, sizeof(test_buffer));
    if (result) {
        printf("ERROR: Buffer write failed\r\n");
        return -7;  // Buffer write failed
    }

    eeprom_read_buffer(test_address + 8, read_buffer, sizeof(read_buffer));
    for (int i = 0; i < sizeof(test_buffer); i++) {
        if (read_buffer[i] != test_buffer[i]) {
            printf("ERROR: Buffer read data mismatch at index %d. Expected: 0x%02X, Got: 0x%02X\r\n", 
                   i, test_buffer[i], read_buffer[i]);
            return -8;  // Buffer read data mismatch
        }
    }
    printf("Buffer write/read test PASSED\r\n");

    

    printf("All EEPROM tests PASSED\r\n");
    return 0;  // All tests passed
}

